/**
 * Return signed random integer from given range
 * rand(25); equals rand(0, 25);
 * @param min Number
 * @param [max] Number
 */
function rand( min, max ) { return max ? Math.floor(Math.random() * (max - min + 1)) + min : Math.floor(Math.random() * (min + 1));}
Array.prototype.random = function(){ return this[rand(this.length-1)]};

/**
 * Cell
 */
function CellClass(x, y, dom){
	this.dom = dom;
	this.x = x;
	this.y = y;
    this.color = app.colors.random();
	this.changedOnStep = 0;
}

/**
 * Change color
 */
CellClass.prototype.changeColor = function(color, depth, step){
    depth = depth || 0;
	
	if(this.changedOnStep == step)
        return;
	this.changedOnStep = step;
    if(depth > 0)
    {
        for(var i=0; i<4; i++){
            var cell = this.getNeighborCell(i);
            if(cell){
                if(cell.color == this.color || cell.color == '#'+color)
                    cell.changeColor(color, depth, step);
            }
        }
    }
	this.setColor(color);
	app.cellsInRegion++;
};

/**
 * SetColor
 */
CellClass.prototype.setColor = function(color){
	this.color = '#'+ color;
	this.dom.style.backgroundColor = this.color;
};

/**
 * GetNeighbourCell
 */
CellClass.prototype.getNeighborCell = function(n){
    var map = [{x:-1, y:0}, {x:0, y:-1}, {x:1,y:0}, {x:0,y:1}];
    var x = this.x + map[n].x;
    var y = this.y + map[n].y;
    if((x<0)||x>app.cellColls-1) return null;
    if((y<0)||y>app.cellRows-1) return null;
    return app.cells[x][y];
};



window.app = new (function(){
    this.colors = [ 'cc0000', '00cc00', '0000ff', 'cc00cc', 'cccc00', '00cccc'];
	/**
	 * if enable is false then block color buttons's clicks
	 */
	this.enable = true;
    /**
     * Array of array of Cell
     * @type Array
     * @return Array
     */
    this.cells = [];
	this.mapDom = null;
    this.cellRows = 15;
    this.cellcolls = 15;
	this.stepCount = 0;
	this.userStep = 0;
	this.score = 10000;
	this.bestScore = 0;
	this.cellsInRegion = 0;

    this.renderButtons = function() {
        var self = this;
        var buttonsPanel = document.getElementById('buttons');
        buttonsPanel.innerHTML = '';
        for (var i = 0; i < this.colors.length; i++) {
            var color = this.colors[i];
            var button = document.createElement('div');
            button.style.backgroundColor = '#' + color;
            button.color = color;
            button.onclick = function() {
                self.step(this.color);
            };
            buttonsPanel.appendChild(button);
        }
    }
    /**
     * Run first, run once.
     * Call on document.ready
     */
    this.init = function(mapDom){
        var self = this;
		this.mapDom = mapDom;
    };

    this.initCells = function () {
        this.cells = [];
		this.mapDom.innerHTML='';
        for (var i = 0; i < this.cellRows; i++) {
            var a = [];
			var tr = document.createElement('tr');
            for(var j=0; j< this.cellColls; j++){
				var dom = document.createElement('td');
				var cell = new CellClass(i,j,dom);
                a.push(cell);
				tr.appendChild(dom);
				cell.setColor(cell.color);
            }
            this.cells.push(a);
			this.mapDom.appendChild(tr);
        }
        return this.cells;
    };

    /**
     * Start new game
     */
    this.start = function(){
		this.enable = true;
        var rows = document.getElementById('rows_count').value;
        var colls = document.getElementById('cols_count').value;
        this.cellRows = parseInt(rows) || 15, document.getElementById('rows_count').value = this.cellRows;
        this.cellColls = parseInt(colls) || 15, document.getElementById('cols_count').value = this.cellColls;
        this.initCells();
        this.renderButtons();
		this.updateUserStep(0);
		this.updateScore(10000);
    };

    /**
     *  Step-over game
     */
    this.step = function(color){
		if(!this.enable) return;
		this.stepCount++;
		this.cellsInRegion = 0;
		this.updateUserStep();
        this.cells[0][0].changeColor(color, 1, this.stepCount);
		this.updateScore();
		this.checkWin();
    }

    /**
     *  Check win
     */
    this.checkWin = function(){
		if(this.cellsInRegion == (this.cellColls*this.cellRows)){
			var mes = 'You win!';
			this.score > this.bestScore ? (this.bestScore = this.score, document.getElementById('best').innerHTML = this.bestScore, mes += ' Best result!' ) : null;
			this.enable = false;
			alert(mes);
		}
    }

    /**
     *  UpdateUserStep
     */
    this.updateUserStep = function(v){
		typeof v == 'number' ? this.userStep = v : this.userStep++;
		document.getElementById('step').innerHTML = this.userStep;
    }

    /**
     *  UpdateScore
     */
    this.updateScore = function(v){
		typeof v == 'number' ? this.score = v : this.score = this.score - Math.floor(this.score * 0.05);
		document.getElementById('score').innerHTML = this.score < 10000 ? this.score : 0;
    }
})();
